package no.medlemsliste.dao.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import no.medlemsliste.dao.MedlemDAO;
import tod141.medlemsliste.model.Endringer;
import tod141.medlemsliste.model.Medlem;
import tod141.medlemsliste.utilities.DAOException;

public class MedlemDAOImpl implements MedlemDAO {

	public void nyttMedlem(Medlem medlem) throws DAOException {
		Connection conn = null;
		PreparedStatement ps = null;
		Statement st = null;
		Exception daoE=null;

		try {
			conn = DatabaseHelper.getConnection("java:comp/env/jdbc/TOD141_Medlemsbase");
			conn.setAutoCommit(false);

			String SQL = "INSERT INTO Medlem (medlemId,fornavn,etternavn,adresse,telefon)";
			SQL = SQL + " VALUES (?,?,?,?,?)";
			ps = conn.prepareStatement(SQL);
			ps.setInt(1, medlem.getMedlemId());
			ps.setString(2, medlem.getFornavn());
			ps.setString(3, medlem.getEtternavn());
			ps.setString(4, medlem.getAdresse());
			ps.setString(5, medlem.getTelefon());
			int ant = ps.executeUpdate();

			if (ant != 1) throw new DAOException("Oppdatering a medlem feilet."); 
			// Oppdaterer logg
			SQL = "INSERT INTO Logg (medlemId,hendelse) VALUES (LAST_INSERT_ID(),'ny')";
			st = conn.createStatement();
			ant = st.executeUpdate(SQL);
			if (ant != 1) throw new DAOException("Oppdatering av logg feilet.");
			conn.commit();
		} catch (Exception e) {
			daoE=e;
		} finally {
			DatabaseHelper.r(conn);
			DatabaseHelper.close(ps);
			DatabaseHelper.close(st);
			DatabaseHelper.close(conn);
			if (daoE != null) throw new DAOException(daoE);
		}
	}

	public void endreMedlem(Medlem medlem) throws DAOException {
		Connection conn = null;
		PreparedStatement ps = null;
		Exception daoE=null;

		try {
			conn = DatabaseHelper.getConnection("java:comp/env/jdbc/TOD141_Medlemsbase");
			conn.setAutoCommit(false);

			String SQL = "UPDATE Medlem set fornavn=?,etternavn=?,adresse=?,telefon=?";
			SQL = SQL + " WHERE medlemId=?";
			ps = conn.prepareStatement(SQL);
			ps.setString(1, medlem.getFornavn());
			ps.setString(2, medlem.getEtternavn());
			ps.setString(3, medlem.getAdresse());
			ps.setString(4, medlem.getTelefon());
			ps.setInt(5, medlem.getMedlemId());
			int ant = ps.executeUpdate();

			if (ant != 1) {
				/* Hva nå? Noen andre har slettet medlem. Kan legge medlem inn på nytt,
				* evt. sende exception.
				* Dersom medlem skal legges inn på nytt må vi først sjekke om medlem finnes og
				* låse rekken.
				*/
				throw new DAOException("Innsettting av medlem feilet.");
			}
			
			// Oppdaterer logg
			SQL = "INSERT INTO Logg (medlemId,hendelse) VALUES (?,'endret')";
			ps = conn.prepareStatement(SQL);
			ps.setInt(1, medlem.getMedlemId());
			ant = ps.executeUpdate();
			if (ant != 1) throw new DAOException("Oppdatering av logg feilet.");
			conn.commit();
		} catch (Exception e) {
			daoE=e;
		} finally {
			DatabaseHelper.r(conn);
			DatabaseHelper.close(ps);
			DatabaseHelper.close(conn);
			if (daoE != null) throw new DAOException(daoE);
		}
	}

	public void slettMedlem(int medlemId) throws DAOException {
		Connection conn = null;
		PreparedStatement ps = null;
		Exception daoE = null;

		try {
			conn = DatabaseHelper.getConnection("java:comp/env/jdbc/TOD141_Medlemsbase");
			conn.setAutoCommit(false);

			String SQL = "DELETE FROM Medlem WHERE medlemId=?";
			ps = conn.prepareStatement(SQL);
			ps.setInt(1, medlemId);
			int ant = ps.executeUpdate();

			if (ant != 1) throw new DAOException("Sletting feilet.");
			// Oppdaterer logg
			SQL = "INSERT INTO Logg (medlemId,hendelse) VALUES (?,'slettet')";
			ps = conn.prepareStatement(SQL);
			ps.setInt(1, medlemId);
			ant = ps.executeUpdate();
			if (ant != 1)  throw new DAOException("Oppdatering av logg feilet.");
			conn.commit();
		} catch (Exception e) {
			daoE = e;
		} finally {
			DatabaseHelper.r(conn);
			DatabaseHelper.close(ps);
			DatabaseHelper.close(conn);
			if (daoE != null) throw new DAOException(daoE);
		}
	}

	public Endringer hentEndringer(int loggId) throws DAOException {
		Endringer endringer = new Endringer();
		if (loggId < 0) {
			endringer = hentAlleMedlemmer();
		} else {
			endringer = hentMedlemmer(loggId);
		}
		
		return endringer;
	}

	private Endringer hentMedlemmer(int loggId) throws DAOException {
		Connection conn = null;
		Statement stAlle = null;
		PreparedStatement psMId = null;
		ResultSet rsMId = null;

		PreparedStatement psH = null;
		ResultSet rsH = null;

		PreparedStatement psM = null;
		ResultSet rsM = null;

		Exception daoE=null;

		Endringer endringer=null;
		try {
			conn = DatabaseHelper.getConnection("java:comp/env/jdbc/TOD141_Medlemsbase");
			conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);

			stAlle = conn.createStatement();

			// Må finnes siste oppslag i logg for hvert medlem
			//String SQL = "SELECT medlemId FROM Logg WHERE loggId>? GROUP BY medlemId";
			String SQL = "SELECT DISTINCT medlemId FROM Logg where loggId > ?";
			psMId = conn.prepareStatement(SQL);
            // SQL = "SELECT hendelse FROM Logg WHERE medlemId=?";
            String SQLh = "SELECT hendelse FROM Logg WHERE medlemId=? ORDER BY loggId DESC LIMIT 1";
            psH = conn.prepareStatement(SQLh);
            String SQLm = "SELECT fornavn,etternavn,adresse,telefon FROM Medlem";
            SQLm = SQLm + " WHERE medlemId=?";
            psM = conn.prepareStatement(SQLm);

            List<Medlem> nyeMedlemmer = new ArrayList<Medlem>();
			List<Medlem> endredeMedlemmer = new ArrayList<Medlem>();
			List<Integer> slettedeMedlemmer = new ArrayList<Integer>();

			psMId.setInt(1, loggId);
            rsMId = psMId.executeQuery();
            int medlemId;
			while (rsMId.next()) {
				medlemId = rsMId.getInt("medlemId");
				psH.setInt(1, medlemId);
				rsH = psH.executeQuery();
				rsH.next();					
				String hendelse = rsH.getString("hendelse");
				if (hendelse.equals("slettet")) {
					slettedeMedlemmer.add(medlemId);
				} else {
					psM.setInt(1, medlemId);
					rsM = psM.executeQuery();
					rsM.next();
					Medlem medlem = new Medlem();
					medlem.setMedlemId(medlemId);
					medlem.setFornavn(rsM.getString("fornavn"));
					medlem.setEtternavn(rsM.getString("etternavn"));
					medlem.setAdresse(rsM.getString("adresse"));
					medlem.setTelefon(rsM.getString("telefon"));
					if (hendelse.equals("ny")) {
						nyeMedlemmer.add(medlem);
					} else if (hendelse.equals("endret")) {
						endredeMedlemmer.add(medlem);
					}
				}
			}
			endringer = new Endringer();

			int loggIdSiste = getMaxLoggId(stAlle,rsMId);
			endringer.setLoggId(loggIdSiste);

			if (nyeMedlemmer.size()>0) {
				endringer.setNyeMedlemmer(nyeMedlemmer);
			}
			if (endredeMedlemmer.size()>0) {
				endringer.setEndredeMedlemmer(endredeMedlemmer);
			}
			if (slettedeMedlemmer.size()>0) {
				endringer.setSlettedeMedlemmer(slettedeMedlemmer);
			}
		} catch (Exception e) {
			daoE = e;
		} finally {
			DatabaseHelper.close(rsM);
			DatabaseHelper.close(rsH);
			DatabaseHelper.close(rsMId);
			DatabaseHelper.close(stAlle);
			DatabaseHelper.close(psMId);
			DatabaseHelper.close(psH);
			DatabaseHelper.close(psM);
			DatabaseHelper.close(conn);
			if (daoE != null) throw new DAOException(daoE);
		}
		return endringer;
	}

	private Endringer hentAlleMedlemmer() throws DAOException {
		Connection conn = null;
		Statement st = null;
		ResultSet rs = null;
		Endringer endringer=null;
		Exception daoE=null;

		try {
			conn = DatabaseHelper.getConnection("java:comp/env/jdbc/TOD141_Medlemsbase");
			conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
			st = conn.createStatement();
			endringer = hentAlle(st,rs);
		} catch (Exception e) {
			daoE = e;
		} finally {
			DatabaseHelper.close(st);
			DatabaseHelper.close(rs);
			DatabaseHelper.close(conn);
			if (daoE != null) throw new DAOException(daoE);
		}
		return endringer;
	}

	private Endringer hentAlle(Statement st,ResultSet rs) throws SQLException {
		Endringer endringer = new Endringer();
		String SQL = "SELECT medlemId,fornavn,etternavn,adresse,telefon FROM Medlem";
		rs = st.executeQuery(SQL);

		List<Medlem> nyeMedlemmer = new ArrayList<Medlem>();
		while (rs.next()) {
			Medlem medlem = new Medlem();
			medlem.setMedlemId(rs.getInt("medlemId"));
			medlem.setFornavn(rs.getString("fornavn"));
			medlem.setEtternavn(rs.getString("etternavn"));
			medlem.setAdresse(rs.getString("adresse"));
			medlem.setTelefon(rs.getString("telefon"));
			nyeMedlemmer.add(medlem);
		}

		int loggIdSiste = getMaxLoggId(st,rs);
		endringer.setLoggId(loggIdSiste);

		if (nyeMedlemmer.size() > 0) {
			endringer.setNyeMedlemmer(nyeMedlemmer);
		}
		return endringer;
	}

	private int getMaxLoggId(Statement st,ResultSet rs) throws SQLException {
		int loggIdSiste;
		String SQL = "SELECT MAX(loggId) AS loggId FROM Logg";
		rs = st.executeQuery(SQL);
		if (rs.next()) {
			loggIdSiste=rs.getInt("loggId");
		} else {
			loggIdSiste=0;
		}
		return loggIdSiste;
	}
}
